﻿==============================================================================
DOSYA ADI  : ReconnectSuspend.cpp
KAYNAK      : -GameServer\ReconnectSuspend.cpp
SISTEM      : v2369 Reconnect - SUNUCU
BOYUT       : 4988 bayt / 177 satir
ACIKLAMA    : SUSPENDED durum cekirdegi - implementasyon
==============================================================================

--- DOSYA ICERIGI ASAGIDAKI GIBIDIR ------------------------------------

#include "stdafx.h"
#include "ReconnectSuspend.h"

namespace Reconnect
{
	const char* ToString(SuspendResult result)
	{
		switch (result)
		{
		case SuspendResult::Confirmed:				return "confirmed";
		case SuspendResult::NotSuspended:			return "not_suspended";
		case SuspendResult::Expired:				return "expired";
		case SuspendResult::TokenMismatch:			return "token_mismatch";
		case SuspendResult::AccountMismatch:		return "account_mismatch";
		case SuspendResult::CharacterMismatch:		return "character_mismatch";
		case SuspendResult::CharacterIDMismatch:	return "character_id_mismatch";
		case SuspendResult::SessionMismatch:		return "session_mismatch";
		}
		return "unknown";
	}
}

CReconnectSuspend::CReconnectSuspend()
	: m_active(false)
	, m_holdSeconds(0)
	, m_beginTick(0)
	, m_confirmAttempts(0)
	, m_releaseReason("-")
{
}

bool CReconnectSuspend::Begin(uint8 holdSeconds, const ReconnectIdentity& identity)
{
	// Zaten askıda olan bir oturum tekrar askıya alınamaz.
	if (m_active)
		return false;

	// Kimlik doğrulaması yapılamayacaksa askıya almanın anlamı yok.
	if (!identity.IsUsable())
		return false;

	m_identity = identity;
	m_holdSeconds = holdSeconds;
	m_beginTick = GetTickCount();
	m_confirmAttempts = 0;
	m_releaseReason = "-";
	m_active = true;
	return true;
}

void CReconnectSuspend::Release(const char* reason)
{
	m_active = false;
	m_releaseReason = (reason != nullptr ? reason : "-");
}

bool CReconnectSuspend::IsExpired() const
{
	if (!m_active || m_holdSeconds == 0)
		return false;

	return ElapsedSeconds() >= m_holdSeconds;
}

uint32 CReconnectSuspend::ElapsedSeconds() const
{
	if (!m_active)
		return 0;

	// uint32 farkı, tick sarmalanmasında da doğru sonuç verir.
	return (GetTickCount() - m_beginTick) / 1000;
}

uint32 CReconnectSuspend::RemainingSeconds() const
{
	if (!m_active)
		return 0;

	const uint32 elapsed = ElapsedSeconds();
	return (elapsed >= m_holdSeconds) ? 0 : (m_holdSeconds - elapsed);
}

Reconnect::SuspendResult CReconnectSuspend::Confirm(const ReconnectIdentity& incoming,
	std::string& failReason)
{
	failReason.clear();

	if (!m_active)
	{
		failReason = "no active suspend session";
		return Reconnect::SuspendResult::NotSuspended;
	}

	m_confirmAttempts++;

	// Süre dolduysa onay kabul edilmez.
	if (IsExpired())
	{
		failReason = "hold time expired";
		return Reconnect::SuspendResult::Expired;
	}

	// --- Güvenlik doğrulaması -------------------------------------------
	// token: her zaman zorunlu ve birebir eşleşmeli.
	if (incoming.token != m_identity.token)
	{
		failReason = "token mismatch";
		return Reconnect::SuspendResult::TokenMismatch;
	}

	// hesap adı: paketle geldiyse eşleşmeli.
	if (!incoming.accountID.empty() && incoming.accountID != m_identity.accountID)
	{
		failReason = "account mismatch";
		return Reconnect::SuspendResult::AccountMismatch;
	}

	// karakter adı: paketle geldiyse eşleşmeli.
	if (!incoming.characterName.empty() && incoming.characterName != m_identity.characterName)
	{
		failReason = "character mismatch";
		return Reconnect::SuspendResult::CharacterMismatch;
	}

	// oyun içi karakter ID: paketle geldiyse eşleşmeli.
	if (incoming.characterID != 0 && incoming.characterID != m_identity.characterID)
	{
		failReason = "character id mismatch";
		return Reconnect::SuspendResult::CharacterIDMismatch;
	}

	// oturum (socket) ID: paketle geldiyse ve kayıtlıysa eşleşmeli.
	// Bu, aynı token'ın başka bir oturumdan kullanılmasını engeller.
	if (incoming.socketID != 0 && m_identity.socketID != 0
		&& incoming.socketID != m_identity.socketID)
	{
		failReason = "session (socket) mismatch";
		return Reconnect::SuspendResult::SessionMismatch;
	}

	// Doğrulama başarılı -> askı sona erer, durum IN_GAME'e döner.
	Release("confirmed");
	return Reconnect::SuspendResult::Confirmed;
}

bool CReconnectSuspend::IsAllowedOpcode(uint8 opcode)
{
	switch (opcode)
	{
	case XSafe:					// AC / UI kanalı: onay paketi buradan gelir
	case WIZ_SPEEDHACK_CHECK:	// speed hack heartbeat (AC bozulmasın)
	case WIZ_LOGOUT:			// oyuncu bilinçli olarak çıkış yapabilsin
		return true;

	default:
		// Hareket, saldırı, yetenek, takas, eşya, NPC, chat... hepsi yutulur.
		return false;
	}
}

bool CReconnectSuspend::IsAllowedXSafeSubOpcode(uint8 subOpcode)
{
	switch (subOpcode)
	{
	case WIZ_RECONNECT:					// UI panelinden gelen yanıt kanalı
	case RECONNECT_REQ_CONFIRM:			// panel "Yes" onayı
	case RECONNECT_REQ_CONFIRM_WITH_ID:	// panel "Yes" onayı (karakter ID dahil)
	case RECONNECT_REQ_DISCONNECT_NOW:	// panel "No" -> hemen disconnect
	case XSafeOpCodes::xALIVE:			// anti-cheat canlılık sinyali
	case XSafeOpCodes::LOG:				// anti-cheat log kanalı
	case XSafeOpCodes::AUTHINFO:		// anti-cheat kimlik bilgisi
		return true;

	default:
		return false;
	}
}